#include "TalkWindowShell.h"
#include "TalkWindow.h"
#include <QListWidget>
#include "WindowManager.h"
#include <QMessageBox>
#include <QFile>
#include "QMsgTextEdit.h"
#include "ReceiveFile.h"

extern QString userA;
extern QString gLoginEmployeeID;

 QString gfileName;
 QString gfileData;

TalkWindowShell::TalkWindowShell(QWidget *parent)
	: BasicWindow(parent)
{
	ui.setupUi(this);

	setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
	//setWindowFlag(Qt::WindowType::in)

	initControl();
	initTcpClientSocket();
	initUdpSocket();

	QFile file(":/Resources/MainWindow/MsgHtml/msgtmpl.js");
	file.resize(0);
	if (!file.size()) {
		if (!createJSFile(getEmployeesList())) {
			QMessageBox::information(
				this,
				"提示",
				"JS写入失败",
				QMessageBox::Ok
			);
		}
	}

}

TalkWindowShell::~TalkWindowShell()
{
	WindowManager::getInstance();
}

void TalkWindowShell::addTalkWindow(TalkWindow * talkWindow, TalkWindowItem * talkWindowItem, const QString &uid)
{
	ui.rightStackedWidget->addWidget(talkWindow);

	connect(m_emotionWindow, SIGNAL(signalEmotionWindowHide()),
		talkWindow, SLOT(onSetEmotionBtnStatus()));

	QListWidgetItem *item = new QListWidgetItem(ui.listWidget);
	item->setSelected(true);

	m_talkWindowItemMap.insert(item, talkWindow);

	//talkWindowItem->setHeadPixmap("");
	ui.listWidget->setItemWidget(item, talkWindowItem);

	onTalkWindowItemChicked(item);

	connect(talkWindowItem, &TalkWindowItem::signalCloseClicked,
		[this, item, talkWindow, talkWindowItem]()
	{	
		//qDebug() << "connect(talkWindowItem, &TalkWindowItem::signalCloseClicked";
		this->m_talkWindowItemMap.remove(item);

		int i = this->ui.listWidget->row(item);
		this->ui.listWidget->takeItem(i);
		delete item, talkWindowItem;

		//WindowManager::getInstance()->deleteWindowId(talkWindow->getTalkId());
		talkWindow->close();
		this->ui.rightStackedWidget->removeWidget(talkWindow);
		if (this->ui.rightStackedWidget->count() < 1)
		{
			this->close();
		}

		
	});
}

void TalkWindowShell::setCurrendWidget(QWidget * widget)
{
	ui.rightStackedWidget->setCurrentWidget(widget);
	
}

const QMap<QListWidgetItem*, QWidget*>& TalkWindowShell::getTalkWindowItemMap() const
{
	// TODO: 在此处插入 return 语句
	return m_talkWindowItemMap;
}

void TalkWindowShell::initControl()
{
	loadStyleSheet("TalkWindow");
	setWindowTitle("TalkWindowShell::聊天窗口");

	m_emotionWindow = new EmotionWindow;
	m_emotionWindow->hide();

	ui.splitter->setSizes(QList<int>{154, width() - 154});

	ui.listWidget->setStyle(new CustomProxyStyle(this));

	connect(
		ui.listWidget, SIGNAL(itemClicked(QListWidgetItem *)),
		this, SLOT(onTalkWindowItemChicked(QListWidgetItem *))
	);
	connect(
		m_emotionWindow, SIGNAL(signalEmotionItemClicked(int)),
		this, SLOT(onEmotionItemChicked(int))
	);

	
}

void TalkWindowShell::initTcpClientSocket()
{
	m_tcpClientSocket = new QTcpSocket(this);

	m_tcpClientSocket->connectToHost("127.0.0.1", M_PORT);
}

void TalkWindowShell::initUdpSocket()
{
	m_udpReceiver = new QUdpSocket(this);

	for (quint16 i = M_PORT_UDP; i < M_PORT_UDP + 100; ++i)
	{
		if(m_udpReceiver->bind(i, QAbstractSocket::BindFlag::ShareAddress))
		break;
	}

	connect(
		m_udpReceiver, SIGNAL(readyRead()),
		this, SLOT(processPendingData())
	);
}

QStringList  TalkWindowShell::getEmployeesList()
{	
	QStringList list;

	QSqlQueryModel model;
	model.setQuery("SELECT employeeID FROM tab_employees WHERE status=1;");

	int employeesNum = model.rowCount();

	for (int i = 0; i < employeesNum; i++) {
		list << model.data(model.index(i, 0)).toString();
	}
	
	return list;
}

bool TalkWindowShell::createJSFile(QStringList & employeesList)
{	
	QString strFile;

	QFile readFile(":/Resources/MainWindow/MsgHtml/msgtmpl.txt");
	if (readFile.open(QIODevice::ReadOnly))
	{
		strFile = readFile.readAll();

		
	}
	else
	{
		QMessageBox::information(this, "ts", "没有msgtmpl.txt");
		
	}
	readFile.close();

	QFile writeFile("D:/Qt_vs2017_item/qq/Resources/MainWindow/MsgHtml/msgtmpl.js");
	if (writeFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
	{
		QString strSourceInitNull = "var external = null;";
		QString strSourceInit = "external = channel.objects.external;";
		//QString strSourceNew = "new QWebChannel(qt.webChannelTransport,\
		//	function(channel) {\
		//	external = channel.objects.external;\
		//}\
		//);";
		QString strSourceRecvHtml = "function recvHtml(msg){\r\n\t$(\"#placeholder\").append(external.msgLHtmlTmpl.format(msg));\r\n\twindow.scrollTo(0,document.body.scrollHeight); ;  \r\n};";
		/*QString strSourceRecvHtml;
		QFile strRead(":/Resources/MainWindow/MsgHtml/recvHtml.txt");
		if(strRead.open(QIODevice::ReadOnly))
		{
			strSourceRecvHtml = strRead.readAll();
		}*/

		QString strReplaceInitNull;
		QString strReplaceInit;
		//QString strReplaceNew;
		QString strReplaceRecvHtml;

		for (int i = 0; i < employeesList.count(); i++)
		{
			QString str = strSourceInitNull;
			strReplaceInitNull += str.replace(
				"external",
				QString("external_%1").arg(employeesList.at(i))
			);
			strReplaceInitNull += "\n";

			str = strSourceInit;
			strReplaceInit += str.replace(
				"external",
				QString("external_%1").arg(employeesList.at(i))
			);
			strReplaceInit += "\n";

			//str = strSourceNew;
			//strReplaceNew += str.replace(
			//	"external",
			//	QString("external_%1").arg(employeesList.at(i))
			//);
			//strReplaceNew += "\n";

			str = strSourceRecvHtml;
			str=str.replace(
				"external",
				QString("external_%1").arg(employeesList.at(i))
			);
			strReplaceRecvHtml += str.replace(
				"recvHtml",
				QString("recvHtml_%1").arg(employeesList.at(i))
			);
			strReplaceRecvHtml += "\n";
		}

		strFile.replace(strSourceInitNull, strReplaceInitNull);
		strFile.replace(strSourceInit, strReplaceInit);
		//strFile.replace(strSourceNew, strReplaceNew);
		strFile.replace(strSourceRecvHtml, strReplaceRecvHtml);

		QTextStream stream(&writeFile);
		stream << strFile;

		return true;
	}
	else
	{
		
		QMessageBox::information(this, "ts", "msgtmpl.js操作失败");
	}
	writeFile.close();
	
	return false;
}

QString TalkWindowShell::handleReceivedMsg(QString j, QString msgType, QString data)
{
	QMsgTextEdit edit(nullptr);

	if (msgType == "1"){
		edit.setFontPointSize(10);
		edit.setText(data);
	}
	else if (msgType == "0") {
		for (int i = 0; i < data.length() / 3; ++i)
		{
			edit.addEmotionUrl(data.mid(i * 3, 3).toInt());
		}
	}

	QString html = edit.document()->toHtml();
	return html;
}

void TalkWindowShell::onEmotionItemChicked(int num)
{
	TalkWindow *window = 
		qobject_cast<TalkWindow*>(ui.rightStackedWidget->currentWidget());

	if (window != nullptr) 
	{
		window->addEmotionImage(num);
	}
}

void TalkWindowShell::onTalkWindowItemChicked(QListWidgetItem * item)
{
	ui.rightStackedWidget->setCurrentWidget(m_talkWindowItemMap[item]);
	item->setSelected(true);
}

/*
	【文本】数据包格式：
	群聊标志（0私聊，1群聊） + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
		+ 信息类型（文本） + 数据长度 + 文本数据

	【表情】数据包格式：
	群聊标志（0私聊，1群聊） + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
		+ 信息类型（表情） + 表情个数 + images + 表情数据

	【文件】数据包格式：
	群聊标志（0私聊，1群聊） + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
		+ 信息类型（2文件） + 文件长度 + "bytes" + 文件名称 + "data_begin" + 文件内容

	msgType，信息类型，0是表情，1是文本，2是文件
*/
void TalkWindowShell::updateSendTcpMsg(QString & strData, int msgType, QString fileName)
{
	QSqlQuery query(
		QString("SELECT employeeID FROM tab_accounts WHERE account='%1'")
		.arg(userA)
	);
	query.exec();
	query.next();
	QString employeeID = query.value(0).toString();

	QString strSend;
	TalkWindow* talk = qobject_cast<TalkWindow*>(
		ui.rightStackedWidget->currentWidget()
		);

	QString type;
	if (talk->getTalkId().length() == 4)
	//群
	{
		type = "1";
	}
	else
	{
		type = "0";
	}
	
	int dataLength = strData.length();
	QString strLength = QString::number(dataLength);
	QString length;
	if (msgType == 1)
	{
		if (strLength.length() == 1)
		{
			length = QString("0000") + strLength;
		}
		else if (strLength.length() == 2)
		{
			length = QString("000") + strLength;
		}
		else if (strLength.length() == 3)
		{
			length = QString("00") + strLength;
		}
		else if (strLength.length() == 4)
		{
			length = QString("0") + strLength;
		}
		else if (strLength.length() == 5)
		{
			length = QString("") + strLength;
		}
		else
		{
			QMessageBox::information(this, "ts", "updateSendTcpMsg 文本信息长度错误");
		}

		/*群聊标志（0私聊，1群聊） + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
			+ 信息类型（文本） + 数据长度 + 文本数据*/
		

		strSend = type + employeeID + talk->getTalkId() + "1" + length + strData;
	}
	else if (msgType == 0)
	{
		/*【表情】数据包格式：
			群聊标志（0私聊，1群聊） + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
			+ 信息类型（表情） + 表情个数 + images + 表情数据*/
		strSend = type + employeeID + talk->getTalkId() + "0" + strData;
	}
	else if (msgType == 2)
	{
		/*【文件】数据包格式：
			群聊标志（0私聊，1群聊） + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
			+ 信息类型（2文件） + 文件长度 + "bytes" + 文件名称 + "data_begin" + 文件内容*/
		QString length = QString::number(strData.toUtf8().length());

		strSend = type + employeeID + talk->getTalkId() + "2"
			+ length + "bytes" + fileName + "data_begin" + strData;
	}

	QByteArray sendData;
	sendData.resize(strSend.length());
	sendData = strSend.toUtf8();

	m_tcpClientSocket->write(sendData);

}

/*
	数据包的格式（都是咱们自己进行的，数据约定）

	文本数据包格式：群聊标志 + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
		+ 信息类型(1) + 数据长度 + 数据

	表情数据包格式：群聊标志 + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
		+ 信息类型(0) + 表情个数 + images + 表情名称

	文件数据包格式：群聊标志 + 发信息员工QQ号 + 收信息员工QQ号（群QQ号）
		+ 信息类型(2) + 文件字节数 + bytes + 文件名 + data_begin + 文件数据

	群聊标志占1位，0单聊，1群聊
	信息类型占1位，0表情信息，1文本信息，2文件信息

	QQ号占5位，群QQ号占4位，
	数据长度占5位，
	表情名称占3位，不足3位，前面用0补全
	（这个占位，就是数据宽度的意思，下面有仔细解释）

	注意：
	当群聊标志为0时，则数据包中，就不是【收信息群QQ号】，而是【收信息员工QQ号】
	当群聊标志为1时，则数据包中，就不是【收信息员工QQ号】，而是【收信息群QQ号】

	群聊文本信息，例：
	【1100012001100005Hello】
	【1 10001 2001 1 00005 Hello】
	群聊文本信息解析：【群聊 发送消息的员工QQ号 接收消息的群QQ号 文本类型 数据宽度为5 数据内容】
	表示：QQ号10001 向群2001发送文本信息，长度是5，数据内容为 Hello

	单聊图片信息，例：
	【0100011000201images060】
	【0 10001 10002 0 1images 060】
	单聊图片信息解析：【单聊 发送消息的员工QQ号 接受消息的员工QQ号 图片类型 表情个数 表情名称】
	表示：员工QQ号10001 向员工QQ号10002发送信息 图片类型 1个表情 表情名称60(表情名称不足3位，前面用0补全)

	群聊文件信息，例：
	【1100052001210bytestest.txtdata_beginhelloworld】
	【1 10005 2001 2 10bytes test.txt data_begin helloworld】
	群聊文件信息解析：【群聊 发送消息的员工QQ号 接收消息的群QQ号 文件类型 文件内容长度 文件名 区分符号 文件内容 】
	表示：QQ号10001 向群2001 发送文件信息，文件内容长度是10，文件名test.txt，区分符号data_begin，文件内容helloworld

*/
void TalkWindowShell::processPendingData()
{	
	while (m_udpReceiver->hasPendingDatagrams())
	{	

		QByteArray data;
		data.resize(m_udpReceiver->pendingDatagramSize());

		m_udpReceiver->readDatagram(data.data(), data.size() );

		QString strData = data.data();

		QString windowId;
		QString f = strData.mid(1, 5);
		if (f == gLoginEmployeeID)
		{
			return;
		}

		QString j;
		QString msgType;
		QString strNew;
		if (strData.mid(0, 1) == "0")
		{
			j = strData.mid(6, 5);
			if (j == userA)
			{
				return;
			}

			msgType = strData.mid(11, 1);
			strNew = strData.mid(12);
			if (gLoginEmployeeID != j)
			{
				return;
			}
			windowId = f;
		}
		else if (strData.mid(0, 1) == "1")
		{
			j = strData.mid(6, 4);
			msgType = strData.mid(10, 1);
			strNew = strData.mid(11);

			windowId = j;
		}



		QString strMsg;
		if (msgType == "0")
		{
			strMsg = strNew.mid(7);
			int n = strMsg.size() / 3;


		}
		else if (msgType == "1")
		{
			int n = strNew.mid(0, 5).toInt();
			strMsg = strNew.mid(5);
			


		}
		else if (msgType == "2")
		{
			int n = strNew.left(strNew.indexOf("bytes")).toInt();

			QString fileName = strNew.mid(
				strNew.indexOf("bytes") + 5,
				strNew.indexOf("data_begin") - strNew.indexOf("bytes") - 5
			);

			strMsg = strNew.mid(strNew.indexOf("data_begin") + 10);

			gfileData = strMsg;
			gfileName = fileName;
		}


		QWidget *widget = WindowManager::getInstance()->findWindowId(windowId);

		if (widget)
		{
			onTalkWindowItemChicked(
				getTalkWindowItemMap().key(widget)
			);

			
		}
		else
		{
			//窗口没有打开
			return;
		}

		if (msgType != "2")
		{
			QString html=handleReceivedMsg(f, msgType, strMsg);
			
			TalkWindow*talkWindow = qobject_cast<TalkWindow*>(widget);

			talkWindow->apped(html, f);

		}
		else//文件
		{
			ReceiveFile receive;
			QString str = QString("收到来自") + f + "发来的文件，是否接收？";
			receive.setMsg(str);

			receive.exec();
		}
		
	}
}

void TalkWindowShell::onEmotionBtnChicked(bool)
{
	m_emotionWindow->setVisible(!m_emotionWindow->isVisible());

	QPoint point = this->mapToGlobal(QPoint(0, 0));
	point.setX(point.x() + 170);
	point.setY(point.y() + 220);

	m_emotionWindow->move(point);
}
